﻿using Simple.Admin.System.Dtos;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Volo.Abp.Application.Services;
using Volo.Abp.Domain.Repositories;
using Volo.Abp.Identity;

namespace Simple.Admin.System;

public class MenuAppService : ApplicationService, IMenuAppService
{
    private readonly IMenuEntityRepository _menuRepository;

    private readonly IIdentityUserRepository _identityUserRepository;

    private readonly IRepository<PermissionMenuEntity> _permissionMenuRepository;

    private readonly MenuManager _menuManager;

    public MenuAppService(IMenuEntityRepository menuRepository,
                          IIdentityUserRepository identityUserRepository,
                          IRepository<PermissionMenuEntity> permissionMenuRepository,
                          MenuManager menuManager)
    {
        _menuRepository = menuRepository;
        _identityUserRepository = identityUserRepository;
        _permissionMenuRepository = permissionMenuRepository;
        _menuManager = menuManager;
    }

    public async Task CreateAsync(CreateMenuInput input)
    {
        var entity = new MenuEntity(GuidGenerator.Create());
        ObjectMapper.Map(input, entity);
        await _menuManager.CreateAsync(entity);

    }

    public Task DeleteAsync(Guid id)
    {
        return _menuManager.DeleteAsync(id);
    }

    public async Task<List<MenuDto>> GetListAsync()
    {
        var list = await _menuRepository.GetListAsync();

        var listDto = ObjectMapper.Map<List<MenuEntity>, List<MenuDto>>(list);

        return listDto;
    }

    public async Task<List<MenuTreeDto>> GetMenuTreeListAsync()
    {
        var userId = CurrentUser.Id;
        if (userId is null)
        {
            throw new UnauthorizedAccessException("未登录");
        }


        List<IdentityRole> roles = await _identityUserRepository.GetRolesAsync(userId.Value);
        var roleIds = roles.Select(x => x.Id.ToString()).ToList();

        List<Guid> allMenuIds = [];

        List<PermissionMenuEntity> userPermissionIds = await _permissionMenuRepository.GetListAsync(x => x.ProviderType == Enums.PermissionProviderType.User && x.ProviderKey == userId.Value.ToString());

        List<PermissionMenuEntity> rolePermissionIds = await _permissionMenuRepository.GetListAsync(x => x.ProviderType == Enums.PermissionProviderType.Role && roleIds.Contains(x.ProviderKey));

        allMenuIds.AddRange(userPermissionIds.Select(x => x.MenuId));
        allMenuIds.AddRange(rolePermissionIds.Select(x => x.MenuId));

        List<MenuEntity> menuList = await _menuRepository.GetListAsync(x => allMenuIds.Distinct().Contains(x.Id));


        var listDto = BuiderMenuTree(menuList);

        return listDto;

    }

    public Task UpdateAsync(UpdateMenuInput input)
    {
        throw new NotImplementedException();
    }

    /// <summary>
    /// 将菜单列表转换为树形结构
    /// </summary>
    /// <param name="list"></param>
    /// <returns></returns>
    private List<MenuTreeDto> BuiderMenuTree(List<MenuEntity> list)
    {
        var resultListDto = new List<MenuTreeDto>();

        var dicList = list.Where(x => x.Type == Enums.MenuTypeEnum.Directory)
                          .Select(x => new MenuTreeDto
                          {
                              Id = x.Id,
                              Path = x.Path,
                              Component = x.Component,
                              Type = x.Type,
                              Redirect = x.Redirect,
                              ParentId = null,
                              Name = x.Name,
                              Meta = new RouteMeta()
                              {
                                  Title = x.Title,
                                  Icon = x.Icon,
                                  KeepAlive = x.KeepAlive,
                                  HideInMenu = x.HideInMenu,
                                  HideChildrenInMenu = x.HideChildrenInMenu,
                                  ActiveIcon = x.ActiveIcon,
                                  MaxNumOfOpenTab = x.MaxNumOfOpenTab,
                                  BadgeType = x.BadgeType,
                                  BadgeVariants = x.BadgeVariants,
                                  ActivePath = x.ActivePath,
                                  Link = x.Link,
                                  IframeSrc = x.IframeSrc,
                                  Query = x.Query,
                                  HideInTab = x.HideInTab,
                                  Authority = x.Authority,
                                  AffixTab = x.AffixTab,
                                  Order = x.Order,
                                  OpenInNewWindow = x.OpenInNewWindow,
                                  NoBasicLayout = x.NoBasicLayout,
                                  IgnoreAccess = x.IgnoreAccess,
                                  HideInBreadcrumb = x.HideInBreadcrumb,
                                  Loaded = x.Loaded,
                                  MenuVisibleWithForbidden = x.MenuVisibleWithForbidden,
                                  AffixTabOrder = x.AffixTabOrder,
                                  Badge = x.Badge

                              }
                          })
                          .ToDictionary(x => x.Id, x => x);

        var menuList = list.Where(x => x.Type == Enums.MenuTypeEnum.Menu)
                         .Select(x => new MenuTreeDto
                         {
                             Id = x.Id,
                             Path = x.Path,
                             Component = x.Component,
                             Type = x.Type,
                             Redirect = x.Redirect,
                             ParentId = x.ParentId,
                             Name = x.Name,
                             Meta = new RouteMeta()
                             {
                                 Title = x.Title,
                                 Icon = x.Icon,
                                 KeepAlive = x.KeepAlive,
                                 HideInMenu = x.HideInMenu,
                                 HideChildrenInMenu = x.HideChildrenInMenu,
                                 ActiveIcon = x.ActiveIcon,
                                 MaxNumOfOpenTab = x.MaxNumOfOpenTab,
                                 BadgeType = x.BadgeType,
                                 BadgeVariants = x.BadgeVariants,
                                 ActivePath = x.ActivePath,
                                 Link = x.Link,
                                 IframeSrc = x.IframeSrc,
                                 Query = x.Query,
                                 HideInTab = x.HideInTab,
                                 Authority = x.Authority,
                                 AffixTab = x.AffixTab,
                                 Order = x.Order,
                                 OpenInNewWindow = x.OpenInNewWindow,
                                 NoBasicLayout = x.NoBasicLayout,
                                 IgnoreAccess = x.IgnoreAccess,
                                 HideInBreadcrumb = x.HideInBreadcrumb,
                                 Loaded = x.Loaded,
                                 MenuVisibleWithForbidden = x.MenuVisibleWithForbidden,
                                 AffixTabOrder = x.AffixTabOrder,
                                 Badge = x.Badge

                             }
                         })
                            .ToDictionary(x => x.Id, x => x);

        var butList = list.Where(x => x.Type == Enums.MenuTypeEnum.Button)
                                 .Select(x => new MenuTreeDto
                                 {
                                     Id = x.Id,
                                     Path = x.Path,
                                     Component = x.Component,
                                     Type = x.Type,
                                     Redirect = x.Redirect,
                                     ParentId = x.ParentId,
                                     Name = x.Name,
                                     Meta = new RouteMeta()
                                     {
                                         Title = x.Title,
                                         Icon = x.Icon,
                                         KeepAlive = x.KeepAlive,
                                         HideInMenu = x.HideInMenu,
                                         HideChildrenInMenu = x.HideChildrenInMenu,
                                         ActiveIcon = x.ActiveIcon,
                                         MaxNumOfOpenTab = x.MaxNumOfOpenTab,
                                         BadgeType = x.BadgeType,
                                         BadgeVariants = x.BadgeVariants,
                                         ActivePath = x.ActivePath,
                                         Link = x.Link,
                                         IframeSrc = x.IframeSrc,
                                         Query = x.Query,
                                         HideInTab = x.HideInTab,
                                         Authority = x.Authority,
                                         AffixTab = x.AffixTab,
                                         Order = x.Order,
                                         OpenInNewWindow = x.OpenInNewWindow,
                                         NoBasicLayout = x.NoBasicLayout,
                                         IgnoreAccess = x.IgnoreAccess,
                                         HideInBreadcrumb = x.HideInBreadcrumb,
                                         Loaded = x.Loaded,
                                         MenuVisibleWithForbidden = x.MenuVisibleWithForbidden,
                                         AffixTabOrder = x.AffixTabOrder,
                                         Badge = x.Badge

                                     }
                                 })
                                  .ToDictionary(x => x.Id, x => x);



        foreach (var item in butList.Values)
        {
            if (item.ParentId.HasValue)
            {
                bool re = menuList.TryGetValue(item.ParentId.Value, out var _);
                if (re)
                {
                    menuList[item.ParentId.Value].Children.Add(item);
                }
            }
        }

        foreach (var item in menuList.Values)
        {
            if (item.ParentId.HasValue)
            {
                bool re = dicList.TryGetValue(item.ParentId.Value, out var _);
                if (re)
                {
                    dicList[item.ParentId.Value].Children.Add(item);
                }
            }
            else
            {
                resultListDto.Add(item);
            }
        }

        resultListDto.AddRange(dicList.Values);
        return resultListDto;
    }
}

